home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 August: Tool Chest / Dev.CD Aug 98 TC.toast / What's New? / Software Development Kits / Mac OS USB DDK / MacOS USB DDK 1.0b4 / NeptuneDDK / Examples / SerialBox / ShimSerialStub.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-06-26  |  24.0 KB  |  907 lines  |  [TEXT/CWIE]

  1. /*
  2.     File:        ShimSerialStub.c
  3.  
  4.     Contains:    Routines used to install, remove and run the ".In" and ".Out" serial driver
  5.                 routines for the PC Card Modem ndrv ".Wabbit".
  6.  
  7.     Version:    xxx put version here xxx
  8.  
  9.     Copyright:    © 1996-1998 by Apple Computer, Inc., all rights reserved.
  10.  
  11.  
  12. */
  13.  
  14. #define PBVERSION1 1
  15.  
  16. #include <LowMem.h>
  17. #include <NameRegistry.h>
  18. #include <TextUtils.h>
  19. #include <stdio.h>
  20. #include <String.h>
  21. #include <Traps.h>
  22.  
  23. #include "ShimSerialStub.h"
  24. #include "ShimSerialInternal.h"
  25.  
  26. #define _DriverInstall    0xA43D
  27. #define _DriverRemove    0xA03E
  28.  
  29. #define DebugMessage(x) SysDebugStr(x)
  30. // #define DebugMessage(x) 
  31.  
  32. #ifndef TraceMessage
  33. #define TraceMessage(i,x) { static local_enable = i; if (local_enable) USBExpertStatus(0, x, 0); local_enable = local_enable; }
  34. //#define TraceMessage(i,x) { static local_enable = i; if (local_enable) SysDebugStr(x); local_enable = local_enable; }
  35. #endif
  36.  
  37.     /* Incorporate debugging strings */
  38. #define noteError(s)    sprintf((char*)context->errorString,"%s",s);
  39.  
  40. //
  41. //     Create the ".In" and ".Out" driver header structures.  While the PC Card
  42. //  Manager requires an 'ndrv' to be attached to the card node in the Name 
  43. //    Registry, the current model for the Serial Driver requires a ".In" and  
  44. //    ".Out" DRVR.  In order to work around the conflicting models,we use the 
  45. //    ndrv to install these driver headers in the Unit Table for the Serial 
  46. //    Driver's use.
  47. //
  48. EJFDRVRHeader slotIn = {
  49.     (1 << dReadEnable | 1 << dCtlEnable | 1 << dStatEnable | 1 << dNeedLock) << 8,
  50.     0,
  51.     0,
  52.     0,
  53.     32 + 0 * sizeof(RoutineDescriptor),
  54.     32 + 1 * sizeof(RoutineDescriptor),
  55.     32 + 2 * sizeof(RoutineDescriptor),
  56.     32 + 3 * sizeof(RoutineDescriptor),
  57.     32 + 4 * sizeof(RoutineDescriptor),
  58.     "\p.slotIn",
  59.     
  60.     BUILD_ROUTINE_DESCRIPTOR(uppDriverProcInfo, &ShimSerialStubOpen),
  61.     BUILD_ROUTINE_DESCRIPTOR(uppDriverProcInfo, &ShimSerialStubPrime),
  62.     BUILD_ROUTINE_DESCRIPTOR(uppDriverProcInfo, &ShimSerialStubControl),
  63.     BUILD_ROUTINE_DESCRIPTOR(uppDriverProcInfo, &ShimSerialStubStatus),
  64.     BUILD_ROUTINE_DESCRIPTOR(uppDriverProcInfo, &ShimSerialStubClose)
  65. };
  66.  
  67.  
  68. EJFDRVRHeader slotOut = {
  69.     (1 << dWritEnable | 1 << dCtlEnable | 1 << dStatEnable | 1 << dNeedLock) << 8,
  70.     0,
  71.     0,
  72.     0,
  73.     32 + 0 * sizeof(RoutineDescriptor),
  74.     32 + 1 * sizeof(RoutineDescriptor),
  75.     32 + 2 * sizeof(RoutineDescriptor),
  76.     32 + 3 * sizeof(RoutineDescriptor),
  77.     32 + 4 * sizeof(RoutineDescriptor),
  78.     "\p.slotOut",
  79.     
  80.     BUILD_ROUTINE_DESCRIPTOR(uppDriverProcInfo, &ShimSerialStubOpen),
  81.     BUILD_ROUTINE_DESCRIPTOR(uppDriverProcInfo, &ShimSerialStubPrime),
  82.     BUILD_ROUTINE_DESCRIPTOR(uppDriverProcInfo, &ShimSerialStubControl),
  83.     BUILD_ROUTINE_DESCRIPTOR(uppDriverProcInfo, &ShimSerialStubStatus),
  84.     BUILD_ROUTINE_DESCRIPTOR(uppDriverProcInfo, &ShimSerialStubClose)
  85. };
  86.  
  87.  
  88.  
  89.  
  90. //
  91. //    Statically define the Icon & Icon Mask for
  92. //    the CRM structures.  In the new world we
  93. //    don't have resources so we have to do it
  94. //    the hard way.
  95. //
  96. UInt32 CRMDeviceIcon[] = {
  97.     0x00000000, 0x00000000, 0x00000000, 0x00000000,
  98.     0x00000000, 0x00000000, 0x07FFFFFF, 0x78000001,
  99.     0x80780001, 0x804C0021, 0x804E0041, 0x80420081,
  100.     0x80420101, 0x80420201, 0x80FF0401, 0x88818801,
  101.     0x98819001, 0xB8FF2001, 0x98004C01, 0x88009A01,
  102.     0x80011601, 0x80021401, 0x80040A01, 0x80080561,
  103.     0x801002D1, 0x80200131, 0x804000E1, 0x80000001,
  104.     0x78000001, 0x07FFFFFF, 0x00000000, 0x00000000,
  105.     0x00000000, 0x00000000, 0x00000000, 0x00000000,
  106.     0x00000000, 0x00000000, 0x07FFFFFF, 0x7FFFFFFF,
  107.     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
  108.     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
  109.     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
  110.     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
  111.     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
  112.     0x7FFFFFFF, 0x07FFFFFF, 0x00000000, 0x00000000
  113. };
  114.  
  115.  
  116. /***********************************************************************************/
  117. //    Function:        InstallDriverControlEntries()
  118. //    Description:    This routine installs the ".In" and ".Out" entries in the Unit
  119. //                    Table.
  120. //
  121. //    Input:            Nothing
  122. //    Output:            Results
  123. /***********************************************************************************/
  124.  
  125. OSErr InstallDriverControlEntries()
  126. {
  127.     DriverRefNum                refNum;
  128.     
  129.     TraceMessage(0,"\pEntering InstallDriverControlEntries");
  130.     
  131.     // Create and install input driver stub
  132.     GetUniqueDrvrName(slotIn.drvrName,kDrvrInName);
  133.     refNum = GetUniqueRefNum();
  134.     if (refNum == 0)
  135.         goto bail;
  136.     
  137.     if (noErr != CallInstallDriverProc((UniversalProcPtr)GetOSTrapAddress(_DriverInstall),
  138.                                         (DRVRHeaderPtr)&slotIn,
  139.                                         refNum))
  140.     {
  141.         DebugMessage("\pCouldn't install input driver stub");
  142.         goto bail;
  143.     }
  144.     
  145.     // Save input driver info
  146.     gGlobals->drvrIn = &slotIn;
  147.     gGlobals->refNumIn = refNum;
  148.     gGlobals->dceIn = GetDCtlEntry(refNum);
  149.     
  150.     // Copy input driver info to it's dce
  151.     (**(gGlobals->dceIn)).dCtlFlags = slotIn.drvrCtlFlags;
  152.     (**(gGlobals->dceIn)).dCtlDriver = (Ptr)&slotIn;
  153.     
  154.     
  155.     // Create and install output driver stub
  156.     GetUniqueDrvrName(slotOut.drvrName,kDrvrOutName);
  157.     refNum = GetUniqueRefNum();
  158.     if (refNum == 0)
  159.         goto bail;
  160.     
  161.     if (noErr != CallInstallDriverProc(    (UniversalProcPtr)GetOSTrapAddress(_DriverInstall),
  162.                                         (DRVRHeaderPtr)&slotOut,
  163.                                         refNum))
  164.     {
  165.         DebugMessage("\pCouldn't install input driver stub");
  166.         goto bail;
  167.     }
  168.     
  169.     // Save output driver info
  170.     gGlobals->drvrOut = &slotOut;
  171.     gGlobals->refNumOut = refNum;
  172.     gGlobals->dceOut = GetDCtlEntry(refNum);
  173.     
  174.     // Copy output driver info to it's dce
  175.     (**(gGlobals->dceOut)).dCtlFlags = slotOut.drvrCtlFlags;
  176.     (**(gGlobals->dceOut)).dCtlDriver = (Ptr)&slotOut;
  177.     
  178.     
  179.     if (noErr != InstallCRM())
  180.     {
  181.         DebugMessage("\pCouldn't install CRM");
  182.         goto bail;
  183.     }
  184.     
  185.     return    noErr;
  186.     
  187. bail:
  188.     return openErr;                        //••• use openErr for now but need to replace it
  189. }
  190.  
  191.  
  192.  
  193.  
  194.  
  195. /***********************************************************************************/
  196. //    Function:        UniqueDrvrName()
  197. //    Description:    This returns true if the name parameter is unique in the unit table
  198. //
  199. //    Input:            name
  200. //    Output:            true if name is unique, otherwise false
  201. /***********************************************************************************/
  202.  
  203. Boolean UniqueDrvrName(StringPtr name)
  204. {
  205.     Ptr        curUTableBase;
  206.     short    curUTableEntries;
  207.     short    refNum, unitNum;
  208.     DCtlHandle    dceHandle;
  209.     
  210.     
  211.     TraceMessage(0,"\pEntering UniqueDrvrName");
  212.     
  213.     curUTableEntries = *(short*)0x01D2;
  214.     curUTableBase = LMGetUTableBase();
  215.     
  216.     for (unitNum = 1; unitNum < curUTableEntries; unitNum++)
  217.     {
  218.         refNum = ~unitNum;
  219.         if ((dceHandle = GetDCtlEntry(refNum)) != NULL){
  220.             if (!PStrCmp(name, ((DRVRHeaderPtr)(*dceHandle)->dCtlDriver)->drvrName))
  221.                 return(false);
  222.         }
  223.     }
  224.     return(true);
  225. }
  226.  
  227.  
  228.  
  229.  
  230.  
  231. /***********************************************************************************/
  232. //    Function:        GetUniqueDrvrName()
  233. //    Description:    This routine builds a unique driver name based on the physical
  234. //                    slot of the card and the device number of the function.
  235. //
  236. //    Input:            Drive base name
  237. //    Output:            Driver name.
  238. /***********************************************************************************/
  239.  
  240. void GetUniqueDrvrName(StringPtr name,StringPtr base)
  241. {
  242.     TraceMessage(0,"\pEntering GetUniqueDrvrName");
  243.  
  244.     BlockMoveData(base,name,1 + base[0]);
  245.     
  246.     // check if this name is in use, if so then append a number and check again.
  247.     // continue until a unique name is found.
  248.     if (!UniqueDrvrName(name)){
  249.         name[0]++;
  250.         name[name[0]] = '0';
  251.     }
  252.     // check again, and keep incrementing the value
  253.     while (!UniqueDrvrName(name)){
  254.         name[name[0]]++;
  255.     }
  256.  
  257. }
  258.  
  259.  
  260.  
  261.  
  262.  
  263. /***********************************************************************************/
  264. //    Function:        GetUniqueRefNum()
  265. //    Description:    This routine finds an unused driver reference number in the Unit
  266. //                    Table.
  267. //
  268. //    Input:            Nothing
  269. //    Output:            Driver reference number. 0=the table is full.
  270. /***********************************************************************************/
  271.  
  272. short GetUniqueRefNum(void)
  273. {
  274.     Ptr        curUTableBase, newUTableBase;
  275.     short    curUTableEntries, newUTableEntries;
  276.     short    refNum, unitNum;
  277.     
  278.     TraceMessage(0,"\pEntering GetUniqueRefNum");
  279.     
  280.     curUTableEntries = *(short*)0x01D2;
  281.     curUTableBase = LMGetUTableBase();
  282.     
  283.     for (unitNum = curUTableEntries-1;unitNum >= 48;unitNum--)
  284.     {
  285.         refNum = ~unitNum;
  286.         if (GetDCtlEntry(refNum) == NULL)
  287.             return refNum;
  288.     }
  289.     
  290.     newUTableEntries = curUTableEntries + 32;
  291.     newUTableBase = NewPtrSysClear((long)newUTableEntries * sizeof(Handle));
  292.     if (newUTableBase == NULL)
  293.         return 0;        /* can't find/make an open slot */
  294.     
  295.     BlockMoveData(curUTableBase,newUTableBase,(long)curUTableEntries * sizeof(Handle));
  296.     LMSetUTableBase(newUTableBase);
  297.     *(short*)0x01D2 = newUTableEntries;
  298.     
  299.     unitNum = newUTableEntries - 1;
  300.     refNum = ~unitNum;
  301.     return refNum;
  302. }
  303.  
  304.  
  305.  
  306.  
  307.  
  308. /***********************************************************************************/
  309. //    Function:        InstallCRM()
  310. //    Description:    Installs our device in the Communications Resource Manager's
  311. //                    queue.
  312. //
  313. //    Input:            Nothing
  314. //    Output:            Result
  315. /***********************************************************************************/
  316.  
  317. OSErr InstallCRM(void)
  318. {
  319.     CRMRecPtr        crm;
  320.     CRMSerialPtr    crmser;
  321.     Str255            name;
  322.     
  323.     TraceMessage(0,"\pEntering InstallCRM"); 
  324.     
  325.     crm = NULL;
  326.     crmser = NULL;
  327.     
  328.     
  329.     // Allocate the necessary CRM structures
  330.     crm = (CRMRecPtr)NewPtrSysClear( sizeof(CRMRec));
  331.     if (crm == NULL) 
  332.         goto label_error;
  333.     
  334.     crmser = (CRMSerialPtr)NewPtrSysClear(sizeof(CRMSerialRecord));
  335.     if (crmser == NULL) 
  336.         goto label_error;
  337.     
  338.     // Save copies in our socket descriptor
  339.     gGlobals->crm = crm;
  340.     gGlobals->crmser = crmser;
  341.  
  342.     // Fill in crm fields...
  343.     crm->qType = crmType;
  344.     crm->crmDeviceType = crmSerialDevice;
  345.     crm->crmDeviceID = 0;
  346.     crm->crmAttributes = (UInt32) crmser;
  347.     crm->crmStatus = 0;
  348.     crm->crmRefCon = 'usbd';
  349.     
  350.     // Fill in crmser fields...
  351.     crmser->version = curCRMSerRecVers;
  352.     
  353.     // Fill in the .in / .out driver names
  354.     crmser->inputDriverName = NewString(gGlobals->drvrIn->drvrName);
  355.     if (!crmser->inputDriverName)
  356.         goto label_error;
  357.     HLock((Handle) gGlobals->drvrIn->drvrName);
  358.     
  359.     crmser->outputDriverName = NewString(gGlobals->drvrOut->drvrName);
  360.     if (!crmser->outputDriverName)
  361.         goto label_error;
  362.     HLock((Handle) gGlobals->drvrOut->drvrName);
  363.     
  364.     // Fill in the card name, icon, etc...
  365.     GetUniqueCRMPortName(name);
  366.     crmser->name = NewString(name);
  367.     crmser->deviceIcon = (CRMIconRecord**)NewHandleSysClear(sizeof(CRMIconRecord));
  368.     if (!crmser->deviceIcon)
  369.         goto label_error;
  370.     BlockMoveData(&CRMDeviceIcon[0],&crmser->deviceIcon[0]->oldIcon[0],128);
  371.     BlockMoveData(&CRMDeviceIcon[32],&crmser->deviceIcon[0]->oldMask[0],128);
  372.     
  373.     crmser->ratedSpeed = kMaxBaudRate;
  374.     crmser->maxSpeed = kMaxBaudRate;
  375.     crmser->reserved = 0;
  376.     
  377.     // Install with CRM
  378.     CRMInstall((CRMRecPtr)crm);
  379.     return noErr;
  380.     
  381.     
  382. label_error:
  383.     if (crmser != NULL) 
  384.     {
  385.         if (crmser->inputDriverName != NULL)
  386.             DisposeHandle((Handle)crmser->inputDriverName);
  387.         if (crmser->outputDriverName != NULL)
  388.             DisposeHandle((Handle)crmser->outputDriverName);
  389.         if (crmser->deviceIcon != NULL)
  390.             DisposeHandle((Handle)crmser->deviceIcon);
  391.         DisposePtr((Ptr)crmser);
  392.     }
  393.     
  394.     if (crm != NULL) 
  395.         DisposePtr((Ptr)crm);
  396.     
  397.     return openErr;
  398. }
  399.  
  400.  
  401.  
  402.  
  403.  
  404. /***********************************************************************************/
  405. //    Function:        GetUniqueCRMPortName()
  406. //    Description:    This routine builds a unique port name based on the physical
  407. //                    slot of the card and the device number of the function.
  408. //
  409. //    Input:            Nothing
  410. //    Output:            Driver name.
  411. /***********************************************************************************/
  412.  
  413. void GetUniqueCRMPortName(StringPtr name)
  414. {
  415.     CRMRec                    theCRMRec,*theCRMRecPtr;
  416.     CRMSerialPtr            serialRecPtr;
  417.     UInt32                    iteration;
  418.     
  419.     
  420.     TraceMessage(0,"\pEntering GetUniqueCRMPortName");
  421.     
  422.     // Set good default
  423.     PStrCopy(name,"\pUSB Serial Adapter");
  424.     
  425.     // can we get the real product name from the name registry?
  426.     
  427.     theCRMRec.crmDeviceType = crmSerialDevice;
  428.     theCRMRec.crmDeviceID = 0;
  429.     theCRMRecPtr = &theCRMRec;
  430.     iteration = 2;
  431.     
  432.     while(theCRMRecPtr != NULL)
  433.     {
  434.         theCRMRecPtr = CRMSearch(theCRMRecPtr);
  435.         if (theCRMRecPtr != NULL)
  436.         {
  437.             serialRecPtr = (CRMSerialPtr)theCRMRecPtr->crmAttributes;
  438.             if (!PStrCmp(*serialRecPtr->name,name))
  439.             {
  440.                 if (iteration == 2)
  441.                 {
  442.                     name[0] += 2;
  443.                     if (name[0] > 31)
  444.                         name[0] = 31;
  445.                 }
  446.                 
  447.                 name[name[0] - 1] = ' ';
  448.                 name[name[0]] = '0' + (UInt8)iteration;
  449.                 
  450.                 theCRMRecPtr = &theCRMRec;
  451.                 iteration += 1;
  452.             }
  453.         }
  454.     }
  455. }
  456.  
  457.  
  458.  
  459.  
  460.  
  461. /***********************************************************************************/
  462. //    Function:        RemoveDriverControlEntries()
  463. //    Description:    This routine removes the ".In" and ".Out" entries in the Unit
  464. //                    Table.
  465. //
  466. //    Input:            Nothing
  467. //    Output:            Results
  468. /***********************************************************************************/
  469.  
  470. OSErr RemoveDriverControlEntries(void)
  471. {
  472.     OSErr        err = noErr;
  473.     
  474.     
  475.     TraceMessage(0,"\pEntering RemoveDriverControlEntries");
  476.     
  477.     // Remove our registration with the CRM
  478.     RemoveCRM();
  479.     
  480.     // Remove the input driver from the Unit Table
  481.     err = CallRemoveDriverProc((UniversalProcPtr) GetOSTrapAddress(_DriverRemove), 
  482.                                         gGlobals->refNumIn);
  483.     if (err != noErr)
  484.         DebugMessage("\pCouldn't remove the input driver.");
  485.     
  486.     // Remove the output driver from the Unit Table
  487.     err = CallRemoveDriverProc((UniversalProcPtr) GetOSTrapAddress(_DriverRemove),
  488.                                         gGlobals->refNumOut);
  489.     if (err != noErr)
  490.         DebugMessage("\pCouldn't remove the output driver.");
  491.     
  492.     return err;
  493. }
  494.  
  495.  
  496.  
  497.  
  498.  
  499. /***********************************************************************************/
  500. //    Function:        RemoveCRM()
  501. //    Description:    Removes our device from the Communications Resource Manager's
  502. //                    queue.
  503. //
  504. //    Input:            Nothing
  505. //    Output:            Nothing
  506. /***********************************************************************************/
  507.  
  508. void RemoveCRM(void)
  509. {
  510.     TraceMessage(0,"\pEntering RemoveCRM");
  511.  
  512.     if (gGlobals->crm)
  513.     {
  514.         CRMRemove(gGlobals->crm);
  515.         
  516.         if (gGlobals->crmser)
  517.         {
  518.             DisposeHandle((Handle)gGlobals->crmser->inputDriverName);
  519.             DisposeHandle((Handle)gGlobals->crmser->outputDriverName);
  520.             DisposeHandle((Handle)gGlobals->crmser->deviceIcon);
  521.             DisposePtr((Ptr)gGlobals->crmser);
  522.         }
  523.         
  524.         DisposePtr((Ptr)gGlobals->crm);
  525.     }
  526. }
  527.  
  528.  
  529.  
  530.  
  531.  
  532. /***********************************************************************************/
  533. //    Function:        ShimSerialStubOpen()
  534. //    Description:    Opens the driver.
  535. //
  536. //    Input:            ParmBlkPtr, DCtlPtr
  537. //    Output:            Status
  538. /***********************************************************************************/
  539.  
  540. OSErr ShimSerialStubOpen (ParmBlkPtr pb, DCtlPtr dce)
  541. {
  542.     OSErr        err = noErr;                // assume success
  543.     
  544. #pragma unused (dce)
  545.  
  546.     TraceMessage(0,"\pEntering ShimSerialStubOpen");
  547.  
  548.     // only do the open stuff once per driver pair
  549.     if (gGlobals->openSession == false)
  550.          err = (OSErr) DoOpenSession(pb);
  551.          
  552.     if ( err ) 
  553.         err = openErr;
  554.     
  555.     pb->ioParam.ioResult = err;
  556.     
  557.     return err;    
  558.  
  559. }    /* end of ShimSerialStubOpen()    */
  560.  
  561.  
  562. /***********************************************************************************/
  563. //    Function:        ShimSerialStubClose()
  564. //    Description:    Closes the driver.
  565. //
  566. //    Input:            ParmBlkPtr, DCtlPtr
  567. //    Output:            Status
  568. /***********************************************************************************/
  569.  
  570. OSErr ShimSerialStubClose (ParmBlkPtr pb, DCtlPtr dce)
  571. {
  572.     OSErr        err = noErr;                // assume success
  573.     
  574.     TraceMessage(0,"\pEntering ShimSerialStubClose");
  575. #pragma unused (dce)
  576.  
  577.     // only do the close stuff once per driver pair
  578.     if (gGlobals->openSession)
  579.         err = (OSErr) DoCloseSession(pb);
  580.         
  581.  
  582.     return err;
  583.  
  584. }    /* end of ShimSerialStubClose()    */
  585.  
  586.  
  587. /***********************************************************************************/
  588. //    Function:        ShimSerialStubPrime()
  589. //    Description:    Handles reads and writes to and from the driver.
  590. //
  591. //    Input:            ParmBlkPtr, DCtlPtr
  592. //    Output:            Status
  593. /***********************************************************************************/
  594.  
  595. OSErr ShimSerialStubPrime (ParmBlkPtr pb, DCtlPtr dce)
  596. {
  597.     OSErr        err = noErr;                // assume success
  598.     
  599.     TraceMessage(0,"\pEntering ShimSerialStubPrime");
  600.     //    initialize actual count read
  601.     pb->ioParam.ioActCount = 0;
  602.     
  603.     //    make sure we've something to read or write
  604.     //
  605.     err = (OSErr)((pb->ioParam.ioReqCount) ? 1 : noErr);
  606.     if ( err )
  607.     {
  608.  
  609.         //
  610.         //    is this a read or write?
  611.         //
  612.  
  613.         switch (pb->ioParam.ioTrap & 0x00FF)
  614.         {
  615.             case aRdCmd:
  616.                 TraceMessage(0,"\pPrime - Read!");
  617.                 if ( !gGlobals )
  618.                 {
  619.                     err = readErr;
  620.                     break;
  621.                 }
  622.                 err = B_Read(gGlobals, 0, (IOParam *)pb);
  623.                 if ( err > noErr )
  624.                     gGlobals->pbIn = pb;
  625. #ifdef OLDSTUFF
  626.                 //    if we didn't find our globals, return readErr;
  627.                 if ( !gGlobals )
  628.                 {
  629.                     err = readErr;
  630.                     break;
  631.                 }
  632.         
  633.                 //    attempt to fill read request immediately
  634.                 //    from any pending data in the input buffer
  635.                 err = B_FillReadRequest(gGlobals, (IOParam *) pb);
  636.         
  637.                 //    if read request unsatisfied and we have no uart (card
  638.                 //    was physically removed, etc.) then we better bail out
  639.                 //    now with a readErr rather than leave the client hanging
  640.  
  641.                 // TODO:  How do we check for a device that disappeared
  642.                 //if ( !gGlobals->uartRegs ) 
  643.                 //{
  644.                 //    err = readErr;
  645.                 //    break;
  646.                 //}
  647.         
  648.                 //    otherwise if the request didn't complete, we set
  649.                 //    this request as our new current read pb
  650.                 if ( err > noErr )
  651.                     gGlobals->pbIn = pb;
  652.         
  653.                 //    if software or hardware flow control are in effect
  654.                 //    we prime input mechanism according to buffer levels
  655.                 //    (otherwise, input is enabled and the pb will be
  656.                 //    treated as input characters arrive from the uart)
  657.                 B_InputFlowControl(gGlobals);
  658. #endif //OLDSTUFF        
  659.                 break;
  660.             
  661.             case aWrCmd:
  662.                 //    otherwise set this request as our current write pb
  663.                 gGlobals->pbOut = pb;
  664.                 
  665.                 err = B_Write(gGlobals, 0, (IOParam *)pb);
  666. #ifdef OLDSTUFF
  667.                 //    if we didn't find our globals, return writErr;
  668.                 //    -OR-
  669.                 //    if we have no uart (card was physically removed, etc.)
  670.                 //    then there's no use in trying, there won't be any transmit
  671.                 //    buffer empty interrupts, so just return writErr now...
  672.                 
  673.                 // TODO:  check for device that disappeared.
  674.                 if ((!gGlobals) /* || (!gGlobals->uartRegs) */)
  675.                 { 
  676.                     err = writErr;
  677.                     break;
  678.                 }
  679.         
  680.                 //    otherwise set this request as our current write pb
  681.                 gGlobals->pbOut = pb;
  682.         
  683.                 //    turn on write buffer empty interrupts to prime our write mechanism
  684.                 B_EnableOutput(gGlobals);
  685. #endif //OLDSTUFF        
  686.         
  687.                 break;
  688.         }
  689.     }
  690.     
  691.     // call the IODone routine if err <= noErr
  692.     if (err <= noErr)
  693.         ShimSerialStubIODone(pb,dce,err);
  694.         
  695.     return err;            
  696.  
  697. }    /* end of ShimSerialStubPrime()    */
  698.  
  699. /***********************************************************************************/
  700. //    Function:        ShimSerialStubControl()
  701. //    Description:    Handles control calls to the driver.
  702. //
  703. //    Input:            ParmBlkPtr, DCtlPtr
  704. //    Output:            Status
  705. /***********************************************************************************/
  706.  
  707. OSErr ShimSerialStubControl (ParmBlkPtr pb, DCtlPtr dce)
  708. {
  709.     UInt16        csCode;
  710.     OSErr        err = noErr;                // assume success
  711.     
  712.     TraceMessage(0,"\pEntering ShimSerialStubControl");
  713.     
  714.     // if we didn't find our globals, return controlErr    
  715.     if (!gGlobals)
  716.         return(controlErr);
  717.  
  718.     csCode = pb->cntrlParam.csCode;
  719.     
  720.     if (csCode == killCode)
  721.     {
  722.         //
  723.         //    the ioQueue should have already been dispensed with by
  724.         //    the device manager, so all we need to do is clear our
  725.         //    local pending io flags...  nb: we behave _just like
  726.         //    the serial driver_ : a killIO on one driver is like a
  727.         //    killIO on both... read and write will both be flushed...
  728.         //    what bothers me about this is what if the client only
  729.         //    wanted to kill input _or_ output ?  the device manager
  730.         //    doesn't know that the serial driver treats these calls
  731.         //    on both drivers...  hmmmm...  hope this works, but
  732.         //    i'm not convinced.
  733.         //
  734.         gGlobals->pbIn = nil;
  735.         gGlobals->pbOut = nil;
  736.  
  737.         //
  738.         //    now turn off write buffer empty interrupts
  739.         //
  740.         B_EnableOutput(gGlobals);
  741.  
  742.         //
  743.         //    kill io is always immediate
  744.         //
  745.  
  746.         err = noErr;
  747.     }
  748.     else
  749.     {
  750.         switch (csCode)
  751.  
  752.  
  753.         {
  754.             case goodbye:
  755.                 err = noErr;
  756.                 break;
  757.     
  758.             case kSERDConfiguration:        /* program port speed, bits/char, parity, and stop bits */
  759.                 //    config UInt16 passed as parameter
  760.                 err = B_SerReset(gGlobals, *(UInt16*) pb->cntrlParam.csParam);
  761.                 break;
  762.     
  763.     
  764.             case kSERDInputBuffer:        /* set buffer for chars received with no read pending */
  765.                 //    buffer pointer and buffer length passed as parameters
  766.                 err = B_SetBuffer(gGlobals, *(Ptr*) pb->cntrlParam.csParam, *(UInt16*) (((Ptr) pb->cntrlParam.csParam) + 4));
  767.                 break;
  768.     
  769.     
  770.             case kSERDSerHShake:            /* equivalent to SerHShake, largely obsolete */
  771.             case kSERDHandshake:            /* superset of 10, honors setting of fDTR */
  772.                 //    handshake record passed
  773.                 B_SetSerShk(gGlobals, (SerShk*) pb->cntrlParam.csParam, csCode);
  774.                 break;
  775.     
  776.     
  777.             case kSERDClearBreak:        /* assert break signal on output */
  778.             case kSERDSetBreak:            /* negate break state on output */
  779.                 B_SetBreak(gGlobals, (csCode == kSERDSetBreak));
  780.                 break;
  781.     
  782.     
  783.             case kSERD115KBaud:            /* set 115.2K baud data rate */
  784.                 (void) B_SetBaudRate(gGlobals, 115200);
  785.                 break;
  786.  
  787.             case kSERD230KBaud:
  788.                 err = controlErr;
  789.                 break;
  790.                 
  791.     
  792.             case kSERDBaudRate:                /* set explicit baud rate, other settings unchanged */
  793.                 *(UInt16*) pb->cntrlParam.csParam = B_SetBaudRate(gGlobals, *(UInt16*) pb->cntrlParam.csParam);
  794.                 break;
  795.     
  796.     
  797.             case kSERDAssertDTR:            /* assert DTR output */
  798.             case kSERDNegateDTR:            /* negate DTR output */
  799.                 B_EnableDTR(gGlobals, (csCode == kSERDAssertDTR));
  800.                 break;
  801.     
  802.     
  803.             case kSERDSetPEChar:            /* select char to replace chars with invalid parity */
  804.             case kSERDSetPEAltChar:        /* select char to replace char that replaces chars with invalid parity */
  805.                 B_SetParErrChar(    gGlobals, 
  806.                                     (csCode == kSERDSetPEAltChar),
  807.                                     *(unsigned char*) pb->cntrlParam.csParam, 
  808.                                     *(((unsigned char*) pb->cntrlParam.csParam)+1));
  809.                 break;
  810.     
  811.     
  812.             case kSERDSetXOffFlag:        /* set XOff output flow control (same as receiving XOff) */
  813.             case kSERDClearXOffFlag:    /* clear XOff output flow control (same as receiving XOn) */
  814.                 gGlobals->serStat.xOffHold = (csCode == kSERDSetXOffFlag);
  815.                 B_EnableOutput(gGlobals);
  816.                 break;
  817.     
  818.     
  819.             case kSERDSendXOn:            /* send XOn if input flow control state is XOff */
  820.             case kSERDSendXOnOut:        /* send XOn regardless of input flow control state */
  821.                 B_SendXOn(gGlobals, (csCode == kSERDSendXOn));
  822.                 break;
  823.     
  824.     
  825.             case kSERDSendXOff:                /* send XOff if input flow control state is XOn */
  826.             case kSERDSendXOffOut:            /* send XOff regardless of input flow control state */
  827.                 B_SendXOff(gGlobals, (csCode == kSERDSendXOff));
  828.                 break;
  829.     
  830.             default:
  831.                 err = controlErr;
  832.                 break;
  833.         }
  834.         
  835.         // call the IODone routine if err <= noErr
  836.         if (err <= noErr)
  837.             ShimSerialStubIODone(pb,dce,err);
  838.     }
  839.         
  840.     return err;
  841.  
  842. }    /* end of ShimSerialStubControl()    */
  843.  
  844.  
  845. /***********************************************************************************/
  846. //    Function:        ShimSerialStubStatus()
  847. //    Description:    Handles status calls to the driver.
  848. //
  849. //    Input:            ParmBlkPtr, DCtlPtr
  850. //    Output:            Status
  851. /***********************************************************************************/
  852.  
  853. OSErr ShimSerialStubStatus(ParmBlkPtr pb,DCtlPtr dce)
  854. {
  855.     OSErr        err = noErr;                // assume success
  856.  
  857.     TraceMessage(0,"\pEntering ShimSerialStubStatus");
  858.  
  859.     // if we didn't find our globals, return statusErr    
  860.     if (!gGlobals)
  861.         return(statusErr);
  862.     
  863.     
  864.     switch (pb->cntrlParam.csCode)
  865.     {
  866.         case kSERDInputCount:        /* return characters available */
  867.             *(UInt32*)(&pb->cntrlParam.csParam[0]) = B_SerGetBuf(gGlobals);
  868.             break;
  869.  
  870.         case kSERDStatus:            /* return SerStaRec record information */
  871.             B_SerStatus(gGlobals, (SerStaRec*) pb->cntrlParam.csParam);
  872.             break;
  873.         
  874.         case kSERDVersion:            /* return version number in first byte of csParam */
  875.             *(char *) pb->cntrlParam.csParam = 9;    /* 9 implies that we do > 57.6K */
  876.             break;
  877.         
  878.         default:                    /* Unknown csCode        */
  879.             err = statusErr;
  880.             break;
  881.     }
  882.     
  883.     // call the IODone routine if err <= noErr
  884.     if (err <= noErr)
  885.         ShimSerialStubIODone(pb,dce,err);
  886.  
  887.     return err;
  888. }
  889.  
  890.  
  891. /***********************************************************************************/
  892. //    Function:        ShimSerialStubIODone()
  893. //    Description:    Notifies the Device Manager that the I/O request has completed.
  894. //
  895. //    Input:            DCtlPtr, result
  896. //    Output:            Nothing
  897. /***********************************************************************************/
  898.  
  899. void ShimSerialStubIODone(ParmBlkPtr pb,DCtlPtr dce,OSErr result)
  900. {
  901.     TraceMessage(0,"\pEntering ShimSerialStubIODone");
  902.     
  903.     pb->ioParam.ioResult = result;
  904.     if (!(pb->ioParam.ioTrap & (1 << noQueueBit)))
  905.         CallIODoneProc( LMGetJIODone(), dce, result );
  906. }
  907.